#include "VrAudioMix.h"
#include "AngleAlgorithm.h"
#include "AudioBuffQueue.h"
#include "MixAlgorithm.h"
#include <stdlib.h>
#include <string.h>
#include "utils/log.h"

#ifndef NULL
#define NULL 0
#endif // !NULL


namespace  {
    const float kMinProportionChange = 0.001;       //音频混合计算时，旧方位过度到新方位时最小的过度比例
}

VrAudioMix::VrAudioMix()
: _angleAlgorithm(NULL)
, _audioBuffQueue(NULL)
, _old_indexA(0)
, _old_indexB(0)
, _old_proportionA(0)
, _old_proportionB(0)
, _timePerByte(0)
, _curFrameOffset(0)
, _mixBuff(NULL)
, _mixLen(0)
{
	_angleAlgorithm = new AngleAlgorithm();
	_audioBuffQueue = new AudioBuffQueue();
}

VrAudioMix::~VrAudioMix()
{
	delete _audioBuffQueue;
	_audioBuffQueue = NULL;
	delete _angleAlgorithm;
	_angleAlgorithm = NULL;
    
    if (_mixBuff) {
        delete[] _mixBuff;
        _mixBuff = NULL;
    }
}

int VrAudioMix::clean(){
    _audioBuffQueue->clean();
    return 1;
}

int VrAudioMix::initFormat(int size,float timePerByte){
    _angleAlgorithm->setSize(size);
    _audioBuffQueue->setStreamSize(size);
    _timePerByte = timePerByte;
    return 1;
}

int VrAudioMix::setAngle(float angle) {
	_angleAlgorithm->setAngle(angle);
	return 1;
}

int VrAudioMix::inputBuff(uint8_t* data, uint32_t len, int streamIndex, int64_t presentationTimeUs) {
    //LOGV("VrAudioMix::inputBuff presentationTimeUs:%lld streamIndex:%d",presentationTimeUs,streamIndex);
	return _audioBuffQueue->inputBuff(data, len, streamIndex, presentationTimeUs);
}

//int VrAudioMix::popData(uint32_t dataLen) {
//	return _audioBuffQueue->popBuff();
//}

int64_t VrAudioMix::getFrontPresentationTimeUs() {

	return _audioBuffQueue->getFrontPresentationTimeUs() + _timePerByte * _curFrameOffset;
}

uint32_t VrAudioMix::getCacheCount(){
    return _audioBuffQueue->getCacheCount();
}

int VrAudioMix::outputNotMixBuff(uint8_t** out_data,uint32_t* out_dataLen){
    if (_audioBuffQueue->getFrontBuff(out_data, out_dataLen)) {
        _audioBuffQueue->popBuff();
        return 1;
    }
    return 0;
}

int VrAudioMix::outputBuff(uint32_t in_maxLen,uint8_t** out_data,uint32_t* out_dataLen){


    
    
    int indexA = 0;
    uint8_t* dataA = NULL;
    int lenA = 0;
    
    int indexB = 0;
    uint8_t* dataB = NULL;
    int lenB = 0;
    
    float proportionA = 0;
    float proportionB = 0;
    
    uint8_t* old_dataB = NULL;
    int old_lenB = 0;
    uint8_t* old_dataA = NULL;
    int old_lenA = 0;
    
    //获取计算比例参数
    if (!_angleAlgorithm->getProportion(&indexA, &indexB, &proportionA,&proportionB))
    {
        return 0;
    }
    if (in_maxLen > _mixLen) {
        _mixLen = in_maxLen;
        if (!_mixBuff) {
            delete[] _mixBuff;
            _mixBuff = NULL;
        }
        _mixBuff = new uint8_t[_mixLen];
    }
    int readLen = 0;
    
    //混合参数
    float proportionChange = 1.0f / in_maxLen;
    proportionChange = proportionChange > kMinProportionChange ? proportionChange:kMinProportionChange;
    float startChange = 0.0f;
    
    while (readLen < in_maxLen) {
        //获取新的数据
        if (!_audioBuffQueue->getFrontBuff(indexA, &dataA, &lenA, indexB, &dataB, &lenB))
        {
            break;
        }
        //获取旧的数据
        if (!_audioBuffQueue->getFrontBuff(_old_indexA, &old_dataA, &old_lenA,
                                           _old_indexB, &old_dataB, &old_lenB))
        {
            break;
        }
        
        
        /**
         *  混合数据
         */
        int bufflen = lenA < lenB ? lenA : lenB;
        bufflen = bufflen < old_lenA ? bufflen : old_lenA;
        bufflen = bufflen < old_lenB ? bufflen : old_lenB;
        
        int lastlen = bufflen - _curFrameOffset;
        
        int mixLen = in_maxLen - readLen;
        mixLen = mixLen < lastlen ? mixLen : lastlen;

        //    MixAlgorithm::straight16_smooth(dataA, lenA, dataB, lenB, proportionA, proportionB, old_dataA,old_lenA, old_dataB, old_lenB, _old_proportionA, _old_proportionB);
        //    memcpy(_mixBuff, dataA, len);
        MixAlgorithm::audio16_mix(dataA+_curFrameOffset, proportionA,
                                  dataB+_curFrameOffset, proportionB,
                                  old_dataA+_curFrameOffset, _old_proportionA,
                                  old_dataB+_curFrameOffset, _old_proportionB,
                                  startChange,proportionChange,
                                  _mixBuff+readLen, mixLen);
        
        
        _curFrameOffset += mixLen;
        if (_curFrameOffset >= bufflen) {
            _audioBuffQueue->popBuff();
            _curFrameOffset = 0;
        }
        readLen += mixLen;
        startChange += proportionChange * mixLen;
        
    }

    
    
    
    *out_data = _mixBuff;
    *out_dataLen = readLen;
    
    _old_indexA = indexA;
    _old_indexB = indexB;
    _old_proportionA = proportionA;
    _old_proportionB = proportionB;
    return 1;
}


bool VrAudioMix::mixScenesAudioData(uint8_t* in_buff, int in_buffLen,
                                    uint8_t** out_buff,uint32_t* out_buffLen){
	int indexA = 0;
	uint8_t* dataA = NULL;
	int lenA = 0;

	int indexB = 0;
	uint8_t* dataB = NULL;
	int lenB = 0;

	float proportionA = 0;
	float proportionB = 0;
	
	uint8_t* old_dataB = NULL;
	int old_lenB = 0;
	uint8_t* old_dataA = NULL;
	int old_lenA = 0;
    
    int streamSize = _audioBuffQueue->getStreamSize();
    //获取计算比例参数
	if (!_angleAlgorithm->getProportion(&indexA, &indexB, &proportionA,&proportionB))
	{
		return false;
	}
    if (indexA >= streamSize || indexB >= streamSize) {
        return false;
    }
	
    //获取新的数据
    int oneSize = in_buffLen / streamSize;
    dataA = in_buff + oneSize * indexA;
    dataB = in_buff + oneSize * indexB;
    old_dataA = in_buff + oneSize * _old_indexA;
    old_dataB = in_buff + oneSize * _old_indexB;

    
    if (oneSize > _mixLen) {
        _mixLen = oneSize;
        if (!_mixBuff) {
            delete[] _mixBuff;
            _mixBuff = NULL;
        }
        _mixBuff = new uint8_t[_mixLen];
    }
    MixAlgorithm::audio16_mix(dataA, proportionA, dataB, proportionB,
                              old_dataA, _old_proportionA, old_dataB, _old_proportionB,
                              0,0.001f,
                              _mixBuff, oneSize);
    
	//*out_data = dataA;
    //*out_dataLen = len;
    
	_old_indexA = indexA;
	_old_indexB = indexB;
	_old_proportionA = proportionA;
	_old_proportionB = proportionB;
    *out_buff = _mixBuff;
    *out_buffLen = oneSize;
	return true;

}

bool VrAudioMix::getMixAudioData(int64_t in_sampleTimeUs,
                     uint8_t** out_buff,uint32_t* out_buffLen){
    
    if (!_audioBuffQueue) {
        return false;
    }
    
    if (!_audioBuffQueue->isHasSampleTimeUsData(in_sampleTimeUs)) {
        return false;
    }
    while (1) {
        
        int64_t stu = _audioBuffQueue->getFrontPresentationTimeUs();
        if (stu == in_sampleTimeUs) {
            break;
        }else if (stu >=0){
            _audioBuffQueue->popBuff();
        }else{
            return false;
        }
        
    }
    int indexA = 0;
    uint8_t* dataA = NULL;
    int lenA = 0;
    
    int indexB = 0;
    uint8_t* dataB = NULL;
    int lenB = 0;
    
    float proportionA = 0;
    float proportionB = 0;
    
    uint8_t* old_dataB = NULL;
    int old_lenB = 0;
    uint8_t* old_dataA = NULL;
    int old_lenA = 0;
    
    //获取计算比例参数
    if (!_angleAlgorithm->getProportion(&indexA, &indexB, &proportionA,&proportionB))
    {
        return false;
    }

    
    if (!_audioBuffQueue->getFrontBuff(indexA, &dataA, &lenA, indexB, &dataB, &lenB))
    {
        return false;
    }
    //获取旧的数据
    if (!_audioBuffQueue->getFrontBuff(_old_indexA, &old_dataA, &old_lenA,
                                       _old_indexB, &old_dataB, &old_lenB))
    {
        return false;
    }
    
    //获取新的数据
    int bufflen = lenA < lenB ? lenA : lenB;
    bufflen = bufflen < old_lenA ? bufflen : old_lenA;
    bufflen = bufflen < old_lenB ? bufflen : old_lenB;
    
    
    if (bufflen > _mixLen) {
        _mixLen = bufflen;
        if (!_mixBuff) {
            delete[] _mixBuff;
            _mixBuff = NULL;
        }
        _mixBuff = new uint8_t[_mixLen];
    }
    MixAlgorithm::audio16_mix(dataA, proportionA, dataB, proportionB,
                              old_dataA, _old_proportionA, old_dataB, _old_proportionB,
                              0,0.001f,
                              _mixBuff, bufflen);
    
    
    
    _audioBuffQueue->popBuff();
    
    
    _old_indexA = indexA;
    _old_indexB = indexB;
    _old_proportionA = proportionA;
    _old_proportionB = proportionB;
    *out_buff = _mixBuff;
    *out_buffLen = bufflen;
    
    return true;

}

bool VrAudioMix::outputSampleTimeUs(int64_t* out_sampleTimeUs){
    if (_audioBuffQueue) {
        return _audioBuffQueue->outputSampleTimeUs(out_sampleTimeUs);
    }
    return false;
}
